"""
  Implementation of the "package_docs_content" rule. The implementation runs the
  packager executable in order to group all specified files into the given sections.
"""

def _package_docs_content(ctx):
    # Directory that will contain all grouped input files. This directory will be created
    # relatively to the current target package. (e.g. "bin/src/material-examples/docs-content")
    output_dir = ctx.attr.name

    # Arguments that will be passed to the packager executable.
    args = ctx.actions.args()

    # List of outputs that should be generated by the packager action. Bazel will automatically
    # throw an error if any output has not been generated properly.
    expected_outputs = []

    # Support passing arguments through a parameter file. This is necessary because on Windows
    # there is an argument limit and we need to handle a large amount of input files. Bazel
    # switches between parameter file and normal argument passing based on the operating system.
    # Read more here: https://docs.bazel.build/versions/master/skylark/lib/Args.html#use_param_file
    args.use_param_file(param_file_arg = "--param-file=%s")

    # Walk through each defined input target and the associated section and compute the
    # output file which will be added to the executable arguments.
    for input_target, section_name in ctx.attr.srcs.items():
        section_files = input_target.files.to_list()

        for input_file in section_files:
            # For each input file, we want to create a copy that is stored in the output directory
            # within its specified section. e.g. "pkg_bin/docs-content/guides/getting-started.html"
            output_file = ctx.actions.declare_file(
                "%s/%s/%s" % (output_dir, section_name, input_file.basename),
            )

            # Add the output file to the expected outputs so that Bazel throws an error if the file
            # hasn't been generated properly.
            expected_outputs += [output_file]

            # Pass the input file path and the output file path to the packager executable. We need
            # to do this for each file because we cannot determine the general path to the output
            # directory in a reliable way because Bazel targets cannot just "declare" a directory.
            # See: https://docs.bazel.build/versions/master/skylark/lib/actions.html
            args.add("%s,%s" % (input_file.path, output_file.path))

    # Do nothing if there are no input files. Bazel will throw if we schedule an action
    # that returns no outputs.
    if not ctx.files.srcs:
        return None

    # Run the packager executable that groups the specified source files and writes them
    # to the given output directory.
    ctx.actions.run(
        inputs = ctx.files.srcs,
        executable = ctx.executable._packager,
        outputs = expected_outputs,
        arguments = [args],
        progress_message = "PackageDocsContent",
    )

    return DefaultInfo(files = depset(expected_outputs))

"""
  Rule definition for the "package_docs_content" rule that can accept arbritary source files
  that will be grouped into specified sections. This is being used to package the docs
  content into a desired folder structure that can be shared with the docs application.
"""
package_docs_content = rule(
    implementation = _package_docs_content,
    attrs = {
        # This defines the sources for the "package_docs_content" rule. Instead of just
        # accepting a list of labels, this rule requires the developer to specify a label
        # keyed dictionary. This allows developers to specify where specific targets
        # should be grouped into. This helpful when publishing the docs content because
        # the docs repository does not about the directory structure of the generated files.
        "srcs": attr.label_keyed_string_dict(allow_files = True),

        # Executable for this rule that is responsible for packaging the specified
        # targets into the associated sections.
        "_packager": attr.label(
            default = Label("//tools/package-docs-content"),
            executable = True,
            cfg = "host",
        ),
    },
)
